home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / source / dakit / pbio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-10-22  |  11.2 KB  |  388 lines

  1. /*--pbio.c----------------------------------------------------------*
  2.  *                                    *
  3.  *  Routines to read & write PC Paintbrush files.            *
  4.  *                                    *
  5.  * Date      Who Changes                        *
  6.  * --------- --- -------------------------------------------------- *
  7.  * 31-Mar-89 mjc band read & write to allow large files.        *
  8.  * 19-Apr-89 mjc 256 color palette added at end of paintbrush file. *
  9.  *                                    *
  10.  * TBD: haven't added scroll-offset logic to "to planar" case, since
  11.  * ANIMDISK is only 8 bpp.
  12.  *------------------------------------------------------------------*/
  13.  
  14. #include "main.h"
  15. #include <fcntl.h>
  16. #include <malloc.h>
  17. #include <sys\types.h>
  18. #include <sys\stat.h>
  19. #include <io.h>
  20. #include <stdio.h>
  21.  
  22. #define local static
  23.  
  24. /* RowBytes computes the number of bytes in a row, from the width in pixels.*/
  25. #define RowBytes(w)   (((w) + 15) >> 4 << 1)
  26.  
  27. /*------------------------------------------------------------------
  28.  *            256 Color Palette
  29.  *
  30.  *  When reading the paintbrush file, the 256 color palette is
  31.  *  sought only if the version number in the header is 5 and the
  32.  *  bits per pixel * planes == 8.  The last 769 bytes of the file
  33.  *  must start with 0x0C, and be followed by the 768 byte palette.
  34.  *
  35.  *  When writing the paintbrush file, we write
  36.  *  version 5 in the header, and append the palette to the end of
  37.  *  the file in the same format as above (0x0C followed by 768
  38.  *  bytes of palette).
  39.  *------------------------------------------------------------------
  40.  */
  41.  
  42. /* Return SUCCESS, FAIL, or specific errors ... */
  43. #define PB_NOT_ENUF_MEM        2
  44. #define PB_NO_256_PALETTE    3
  45.  
  46. local WORD readCount;    /* For compression. */
  47. local UBYTE readChar;
  48.  
  49. /* --- Forward declarations. */
  50. void GetByte(WORD file);
  51. BOOL PutBytes(BYTE far * ptr, WORD bytes, WORD file);
  52.  
  53. /*-----------------------------------------------------------------*/
  54.  
  55. typedef struct {
  56.     BYTE manufacturer;
  57.     BYTE version;
  58.     BYTE encoding;
  59.     BYTE bitsperpixel;
  60.     WORD xmin, ymin, xmax, ymax;
  61.     WORD hres, vres;
  62.     BYTE colormap[16][3];
  63.     BYTE reserved;
  64.     BYTE nplanes;
  65.     WORD bytesperline;
  66. } PCPAINTBRUSH_HEADER;
  67.  
  68. local PCPAINTBRUSH_HEADER *pbh = NULL;    /* paintbrush header pointer */
  69.     /* Global pointer so can allocate in header, use fields in body. */
  70.  
  71. /*--------------------- Bad Paintbrush Header ----------------------*/
  72. #define BadPbHeader(s)        (FAIL)
  73.  
  74. /*-------------------- Invalid Paintbrush File ---------------------*/
  75. #define InvalidPbFile()        (FAIL)
  76.  
  77. #define WrongPbFileType()    (FAIL)    /* Expected different data format.*/
  78. #define PCXNo256PaletteMsg()
  79.  
  80. /*-----------------------------------------------------------------*
  81.  *  Read the header of a pc paintbrush file.
  82.  *  Sets bmHdr fields.  Calls reSize if necessary.
  83.  *  Returns SUCCESS or FAIL.
  84.  *-----------------------------------------------------------------*/
  85.  
  86. BOOL ReadPCX_Header(WORD file, BITMAP *bitmap, LONG *palette,
  87.                     BitMapHeader *bmHdr)
  88. {
  89.     register WORD i;
  90.     UBYTE c, palet[256][3];
  91.  
  92.     if (!pbh)            /* Test in case we come through twice w/o freeing. */
  93.         pbh = malloc(sizeof(PCPAINTBRUSH_HEADER) + 4);
  94.     if (!pbh)
  95.         return (FAIL);
  96.  
  97.     if (read(file, (char *)pbh, sizeof(PCPAINTBRUSH_HEADER)) !=
  98.         sizeof(PCPAINTBRUSH_HEADER))
  99.         return (InvalidPbFile());
  100.  
  101.     /* --- To start of pixel data. */
  102.     if (0 > lseek(file, (LONG) 128, SEEK_SET))
  103.         return (InvalidPbFile());
  104.  
  105.     /* --- Check that the header info is valid. */
  106.     if (pbh->manufacturer != 10)
  107.         return (InvalidPbFile());
  108.  
  109.     /* --- Expecting version with palette at end. */
  110.     if (pbh->version != 5)
  111.         return (BadPbHeader(s_wrongPBVersion));
  112.  
  113.     if (pbh->encoding != 1)
  114.         return (BadPbHeader(s_unknownEncoding));
  115.  
  116.     if (pbh->bitsperpixel != 1 && pbh->nplanes != 1)
  117.         return (BadPbHeader(s_wrongLayout));
  118.  
  119.     if (pbh->bitsperpixel != 8)
  120.         return (WrongPbFileType());
  121.  
  122.     /* --- Compute dimensions and # colors. */
  123.     setmem(bmHdr, sizeof(BitMapHeader), 0);
  124.     bmHdr->w = 1 + pbh->xmax - pbh->xmin;
  125.     bmHdr->h = 1 + pbh->ymax - pbh->ymin;
  126.     bmHdr->nPlanes = pbh->bitsperpixel * pbh->nplanes;
  127.             /* MAY BE PACKED. */
  128.  
  129.     /* --- Get the color map. */
  130.     if (palette != NULL) {
  131.         /* If a 256 color palette should be present at the end of the
  132.          * file, try to fetch it from disk and copy it to the palette.
  133.          */
  134.         c = 0;
  135.         if (lseek(file, (LONG)-769, SEEK_END) >= 0)
  136.             if (read(file, &c, 1) == 1)
  137.                 if (read(file, (UBYTE *)&palet[0][0], 768) == 768)
  138.                     if (c == 0x0C)
  139.                         for (i = 0; i < 256; ++i)
  140.                             palette[i] = ((LONG)palet[i][0] << 16) +
  141.                                 ((LONG)palet[i][1] << 8) +
  142.                                 ((LONG)palet[i][2]);
  143.             /* --- To start of pixel data (again). */
  144.             lseek(file, (LONG)128, SEEK_SET);
  145.         if (c != 0x0C) {
  146.             /* ---- We couldn't read a 256 color palette at the end
  147.              * of the file.
  148.              */
  149.             PCXNo256PaletteMsg();
  150.             return (PB_NO_256_PALETTE);
  151.         }
  152.     }
  153.     return (SUCCESS);            /* Header done; BODY yet to do. */
  154. }
  155.  
  156. /*-----------------------------------------------------------------*
  157.  *  Read the pixel data into the bitmap.  Return SUCCESS or FAIL.
  158.  *-----------------------------------------------------------------*/
  159. #define MaxPCXPlanes    8        /* 256-color, no mask. */
  160.  
  161. BOOL ReadPCX_BODY(WORD file, BITMAP *bitmap, BitMapHeader *bmHdr)
  162. {
  163.     register WORD i, iPlane;
  164.     BOOL result = SUCCESS;
  165.     BYTE far *dest;
  166.     WORD bodyNRows, srcPlanesToUse;
  167.     WORD bodyIRow;    /* Increment from 0..bodyNRows-1. */
  168.     BYTE far *dests[MaxPCXPlanes];    /* Ptrs to dest scan lines. */
  169.     WORD useBytes;
  170.  
  171.     /* --------- Initialization. ---------- */
  172.     readCount = 0;                /* For compression. */
  173.  
  174.     bodyNRows = MIN(bmHdr->h, bitmap->box.h);
  175.     srcPlanesToUse = MIN(bitmap->planes + bpp_minus1, bmHdr->nPlanes);
  176.  
  177.     /* ---------- Read all scan lines. ---------- */
  178.     OpenIOBuffer(FALSE);
  179.  
  180.     for (bodyIRow = 0; bodyIRow < bodyNRows; ++bodyIRow) {
  181.         readCount = 0;     /* Just in case, supposed to start anew each line. */
  182.  
  183.         useBytes = MIN(bitmap->width, pbh->bytesperline);
  184.  
  185.         /* ----- Read a scan line. */
  186.         dest = (BYTE far *)BMLineStart(bitmap, bodyIRow, 0);
  187.         for (i = 0; i < pbh->bytesperline; i++) {
  188.             GetByte(file);
  189.             if (i < useBytes)
  190.                 *dest++ = readChar;
  191.         }
  192.     }
  193.     CloseIOBuffer(file);
  194.  
  195. done:
  196.     return (result);
  197. }
  198.  
  199. /*--------------------- Close Paintbrush File ---------------------*/
  200. /* --- NOTE: if change, must change WritePCX_Done, since it calls this. */
  201.  
  202. void ReadPCX_Done()
  203. {
  204.         /* --- Free pbh, which is shared by header & body routines. */
  205.     if (pbh)
  206.         free(pbh);
  207.     pbh = NULL;
  208. }
  209.  
  210. void WritePCX_Done()
  211. {
  212.     ReadPCX_Done();
  213. }
  214.  
  215. /*---------------------------- Get Byte ---------------------------*/
  216. /* Set readCount & readChar.  At EOF or file error, returns 0's forever. */
  217.  
  218. void GetByte(WORD file)
  219. {
  220.     UBYTE c;
  221.  
  222.         /* --- if in the middle of a run of encoded bytes, don't read any
  223.          *    more
  224.          */
  225.     if (readCount > 0) {
  226.         --readCount;
  227.         return;
  228.     }
  229.     readCount = 0;
  230.     if (GReadOne(file, &c) != 1) {
  231. sawEOF:
  232.         readCount = 32767;        /* Huge count of 0's to pad the end. */
  233.         readChar = 0;
  234.         return;
  235.     }
  236.     if ((c & 0xc0) == 0xc0) {
  237.         readCount = (0x3f & c) - 1;        /* "-1": consuming one of count. */
  238.         if (GReadOne(file, &c) != 1)
  239.             goto sawEOF;
  240.     }
  241.     readChar = c;
  242. }
  243.  
  244. /*----------------------------------------------------------------------*
  245.      Output File Routines & Variables
  246.  *----------------------------------------------------------------------*/
  247.  
  248. /*---------------------------------------------------------------*
  249.     Output header for a PC Paintbrush file with the given number
  250.     of bitsperpixel and planes.  One of these two parms must be 1.
  251.     ASSUMES OKAY TO TRASH buffer[].
  252.     Returns SUCCESS or FAIL.
  253.  *---------------------------------------------------------------*/
  254.  
  255. BOOL WritePCX_Header(WORD file, BITMAP *bitmap, LONG *palette)
  256. {
  257.     register PCPAINTBRUSH_HEADER *ppbh;
  258.     WORD i;
  259. #define GAP_SIZE    (128 - sizeof(PCPAINTBRUSH_HEADER))
  260.     UBYTE buffer1[GAP_SIZE];
  261.  
  262.         /* --- init the header that we'll write.
  263.          *        Note: since DPaint never reads & writes at the same time,
  264.          *        it is okay to share the same read & write structure,
  265.          *        unlike in CONVERT.EXE.
  266.          */
  267.     if (!pbh)                    /* Test in case we come through twice w/o
  268.                                  * freeing. */
  269.         pbh = malloc(sizeof(PCPAINTBRUSH_HEADER) + 4);
  270.     if (!pbh)
  271.         return (FAIL);
  272.     ppbh = pbh;                /* Register variable for smaller, faster code. */
  273.  
  274.     setmem(ppbh, sizeof(PCPAINTBRUSH_HEADER) + 4, 0);
  275.     ppbh->manufacturer = 10;
  276.     ppbh->version = 5;
  277.     ppbh->encoding = 1;
  278.  
  279.     ppbh->bitsperpixel = bpp;
  280.     ppbh->xmin = ppbh->ymin = 0;
  281.     ppbh->xmax = bitmap->box.w - 1;
  282.     ppbh->ymax = bitmap->box.h - 1;
  283.     ppbh->hres = N_COLUMNS;
  284.     ppbh->vres = N_LINES;
  285.  
  286.     /* --- bytesperline doesn't take into account multiple planes.
  287.      * Output in same format as bitmap (planar vs packed).
  288.      */
  289.     ppbh->bytesperline = bitmap->width;
  290.  
  291.     ppbh->nplanes = bitmap->planes;
  292.     ppbh->reserved = 0;
  293.  
  294.     /* --- First 16 colors of our palette info. */
  295.     for (i = 0; i < 16; ++i) {
  296.         ppbh->colormap[i][0] = (BYTE)(palette[i] >> 16);
  297.         ppbh->colormap[i][1] = (BYTE)(palette[i] >> 8);
  298.         ppbh->colormap[i][2] = (BYTE) palette[i];
  299.     }
  300.  
  301.     /* --- write the 128-byte header */
  302.     if (GWrite(file, (char *)ppbh, sizeof(PCPAINTBRUSH_HEADER))
  303.         != sizeof(PCPAINTBRUSH_HEADER))
  304.         goto error;
  305.  
  306.     setmem(buffer1, GAP_SIZE, 0);
  307.     if (GWrite(file, buffer1, GAP_SIZE) != GAP_SIZE)
  308. error:
  309.         return (FAIL);
  310.  
  311.     return (SUCCESS);
  312. }
  313.  
  314. /* --------------- WritePCX_BODY ---------------
  315.  *  Write the pixel data.
  316.  *  Returns SUCCESS or an error condition.
  317.  * -------------------------------------------------------------------
  318.  */
  319. WORD WritePCX_BODY(WORD file, BITMAP *bitmap)
  320. {
  321.     register WORD y;
  322.  
  323.     /* --- Write to a bit-packed file. */
  324.     for (y = 0;  y < bitmap->box.h;  ++y) {        /* for each line in band */
  325.         if (PutBytes((BYTE far *)BMLineStart(bitmap, y, 0),
  326.                      pbh->bytesperline, file))
  327.             return FAIL;
  328.     }
  329.     return SUCCESS;
  330. }
  331.  
  332. /*-------------------- Output any 256-color palette ------------------------*/
  333. BOOL WritePCX_256Palette(WORD file, LONG *palette)
  334. {
  335.     register WORD i;
  336.     UBYTE c, palet[256][3];
  337.  
  338.     if (pbh->version == 5 && pbh->bitsperpixel == 8) {
  339.         for (i = 0; i < 256; ++i) {
  340.             palet[i][0] = (BYTE)(palette[i] >> 16);
  341.             palet[i][1] = (BYTE)(palette[i] >> 8);
  342.             palet[i][2] = (BYTE) palette[i];
  343.         }
  344.         c = 0x0C;
  345.         if (GWrite(file, &c, 1) != 1 ||
  346.             GWrite(file, (char *)&palet[0][0], 768) != 768)
  347.             return FAIL;
  348.     }
  349.     return SUCCESS;
  350. }
  351.  
  352. /*-------------------------------------------------------------------
  353.  *    Write bytes to a file, handling packing as it goes.
  354.  *    Returns SUCCESS or FAIL.
  355.  *-------------------------------------------------------------------
  356.  */
  357. BOOL PutBytes(BYTE far *ptr, WORD bytes, WORD file)
  358. {
  359.     register WORD startbyte, count;
  360.     char b;
  361.  
  362.     while (bytes > 0) {
  363.         /* --- check for a repeating byte value */
  364.         startbyte = *ptr++;
  365.         --bytes;
  366.         count = 1;
  367.         while (*ptr == startbyte && bytes > 0 && count < 63) {
  368.             ++ptr;
  369.             --bytes;
  370.             ++count;
  371.         }
  372.         /* --- If we can pack the sequence, or if we have to add a
  373.          * byte before it because the top 2 bits of the value
  374.          * are 1's, write a packed sequence of 2 bytes.
  375.          * Otherwise, just write the byte value.
  376.          */
  377.         if (count > 1  ||  (startbyte & 0xc0) == 0xc0) {
  378.             b = 0xc0 | count;
  379.             if (GWrite(file, &b, 1) != 1)
  380.                 return FAIL;
  381.         }
  382.         b = startbyte;
  383.         if (GWrite(file, &b, 1) != 1)
  384.             return FAIL;
  385.     }
  386.     return SUCCESS;
  387. }
  388.